package main

import (
	"fmt"
	"net/http"
	"html/template"
	"strings"
	"io"
	"os"
	"time"
	"crypto/md5"
	"log"
	"strconv"
)
/*
form的enctype属性，enctype属性有如下三种情况:
application/x-www-form-urlencoded   表示在发送前编码所有字符（默认）
multipart/form-data   不对字符编码。在使用包含文件上传控件的表单时，必须使用该值。
text/plain    空格转换为 "+" 加号，但不对特殊字符编码。
*/
func sayHelloName(w http.ResponseWriter,r *http.Request){
	r.ParseForm()//parse parameters
	fmt.Println("--------------------------------------------")
	fmt.Println(r.Form)
	fmt.Println("path", r.URL.Path)
    fmt.Println("scheme", r.URL.Scheme)
    fmt.Println(r.Form["url_long"])
	for k,v:=range r.Form {
		fmt.Println("key: ",k)
		fmt.Println("val: ",strings.Join(v," "))
	}
	fmt.Fprintf(w, "Hello! Let's test file upload.")
}

func upload(w http.ResponseWriter,r *http.Request){
	fmt.Println("--------------------------------------------")
	fmt.Println("Request Method: ",r.Method)
	fmt.Println("Form data: ",r.Form)
	if r.Method=="GET" {
		curtime:=time.Now().Unix()
		h:=md5.New()
		io.WriteString(h,strconv.FormatInt(curtime,10))
		token:=fmt.Sprintf("%x",h.Sum(nil))
		
		t,_:=template.ParseFiles("uploadfile.gtpl")
		t.Execute(w,token)
	}else{
		/*
		处理文件上传我们需要调用r.ParseMultipartForm，里面的参数表示maxMemory，
		调用ParseMultipartForm之后，上传的文件存储在maxMemory大小的内存里面，
		如果文件大小超过了maxMemory，那么剩下的部分将存储在系统的临时文件中。
		我们可以通过r.FormFile获取上面的文件句柄，然后实例中使用了io.Copy来存储文件。

		获取其他非文件字段信息的时候就不需要调用r.ParseForm，因为在需要的时候Go自动会去调用。
		而且ParseMultipartForm调用一次之后，后面再次调用不会再有效果。

		*/
		r.ParseMultipartForm(32<<20)
		file,handler,er:=r.FormFile("uploadfile")
		if er!=nil{
			fmt.Println("error: ",er)
			return
		}
		defer file.Close()
		fmt.Fprintf(w,"%v",handler.Header)
		fmt.Println("file handler name : ",handler.Filename)
		f,err:=os.OpenFile("d:\\temp\\"+handler.Filename,os.O_WRONLY|os.O_CREATE,0666)
		if err!=nil{
			fmt.Println("error: ",err)
			return
		}
		defer f.Close()
		io.Copy(f,file)
		
		fmt.Println("upload...... ")
		fmt.Fprintf(w,"upload done")
	}
}

func main(){
	http.HandleFunc("/",sayHelloName)
	http.HandleFunc("/upload",upload)
	er:=http.ListenAndServe(":9090",nil)
	if er!=nil{
		log.Fatal("ListenAndServe",er)
	}
}